﻿using Auxiliary.VecMath;
using Simple3DRedactor.Domain;
using Tao.OpenGl;

namespace Simple3DRedactor.OpenGLViewer
{
    class MeshObjectView : GeometryView<MeshObject>
    {
        private bool _rebuild = true;
        private Mesh _oldMesh;
        private int _listId = -1;

        public MeshObjectView(MeshObject obj, ObjectViewFactory factory) : base(obj, factory)
        {
        }

        protected override void PreRenderImpl()
        {
            base.PreRenderImpl();

            if (_rebuild)
            {
                if (_listId < 0)
                    _listId = Gl.glGenLists(1);

                if (InnerObject.Mesh != null)
                {
                    Gl.glNewList(_listId, Gl.GL_COMPILE);

                    // draw each face...
                    foreach (var face in InnerObject.Mesh.Faces)
                    {
                        Gl.glBegin(Gl.GL_POLYGON);

                        for (int i = 0; i < face.VertexIndexies.Count; ++i)
                        {
                            if (InnerObject.Mesh.HasNormals)
                                Gl.glNormal3fv(InnerObject.Mesh.Normals[face.NormalIndexies[i]].ToArray());

                            if (InnerObject.Mesh.HasTextureCoords)
                                Gl.glTexCoord3fv(InnerObject.Mesh.TexCoords[face.TextureIndexies[i]].ToArray());

                            Gl.glVertex3fv(InnerObject.Mesh.Vertices[face.VertexIndexies[i]].ToArray());
                        }

                        Gl.glEnd();
                    }

                    Gl.glEndList();
                }

                _oldMesh = InnerObject.Mesh;
            }

            _rebuild = false;
        }

        protected override void OnObjectChange(SceneObject obj)
        {
            base.OnObjectChange(obj);
            _rebuild = InnerObject.Mesh != _oldMesh;
        }
        
        protected override void RenderImpl()
        {
            Gl.glScalef(InnerObject.Scale.X, InnerObject.Scale.Y, InnerObject.Scale.Z);

            if (InnerObject.Mesh != null)
                Gl.glCallList(_listId);
        }

        protected override Vector3D MaxPoint
        {
            get { return InnerObject.Mesh != null ? InnerObject.Mesh.MaxPoint : Vector3D.Zero; }
        }

        protected override Vector3D MinPoint
        {
            get { return InnerObject.Mesh != null ? InnerObject.Mesh.MinPoint : Vector3D.Zero; }
        }
    }
}
